package com.dd.utils.file

import android.content.Context
import java.io.File
import java.util.Collections
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicLong

class DataCacheManager(
    cacheDir: File,
    sizeLimit: Long,
    countLimit: Int,
    context: Context,
    mMKVManager: DataCacheMMKVManager?
) {
    private var cacheSize: AtomicLong? = null
    private var cacheCount: AtomicInteger? = null
    private var sizeLimit: Long = 0
    private var countLimit = 0
    private val lastUsageDates = Collections.synchronizedMap(HashMap<File, Long>())
    private val mContent: Context
    private var cacheDir: File? = null
    private var mMMKVManager: DataCacheMMKVManager? = null

    init {
        this.cacheDir = cacheDir
        this.sizeLimit = sizeLimit
        this.countLimit = countLimit
        mMMKVManager = mMKVManager
        cacheSize = AtomicLong()
        cacheCount = AtomicInteger()
        mContent = context
        calculateCacheSizeAndCacheCount()
    }

    /**
     * 计算 cacheSize和cacheCount
     */
    private fun calculateCacheSizeAndCacheCount() {
        Thread {
            var size = 0
            var count = 0
            val cachedFiles = cacheDir!!.listFiles()
            if (cachedFiles != null) {
                for (cachedFile in cachedFiles) {
                    size += calculateSize(cachedFile).toInt()
                    count += 1
                    //使用文件本身的属性---最近操作的时间初始化lastUsageDates，或者使用MMKV 将文件映射 的MAP存储下了
                    //lastUsageDates.put(cachedFile, cachedFile.lastModified());
                }
                cacheSize!!.set(size.toLong())
                cacheCount!!.set(count)
            }
            val map: Map<File, Long>? = mMMKVManager?.getUserLastDate(mContent)
            if (null != map) {
                lastUsageDates.putAll(map)
            }
        }.start()
    }

    fun put(file: File) {
        var curCacheCount = cacheCount!!.get()

        //判断文件数量是否大于限制的数量，文件数量不限制
        while (curCacheCount + 1 > countLimit) {
            val freedSize = removeNext()
            cacheSize!!.addAndGet(-freedSize)
            curCacheCount = cacheCount!!.addAndGet(-1)
        }
        cacheCount!!.addAndGet(1)
        val valueSize = calculateSize(file)
        var curCacheSize = cacheSize!!.get()
        //设置了最大存储空间
        while (curCacheSize + valueSize > sizeLimit) {
            val freedSize = removeNext()
            curCacheSize = cacheSize!!.addAndGet(-freedSize)
        }
        cacheSize!!.addAndGet(valueSize)
        val findFile = getFileByKey(file.name)
        if (findFile != null) {
            lastUsageDates.remove(findFile)
        }
        val currentTime = System.currentTimeMillis()
        file.setLastModified(currentTime)
        lastUsageDates[file] = currentTime
    }

    operator fun get(key: String): File {
        val findFile = getFileByKey(key.hashCode().toString())
        if (findFile != null) {
            lastUsageDates.remove(findFile)
        }
        val file = newFile(key)
        val currentTime = System.currentTimeMillis()
        file.setLastModified(currentTime)
        lastUsageDates[file] = currentTime
        return file
    }

    private fun getFileByKey(key: String): File? {
        var findFile: File? = null
        val set: Set<File> = lastUsageDates.keys
        for (file in set) {
            if (key == file.name) {
                findFile = file
                break
            }
        }
        return findFile
    }

    fun newFile(key: String): File {
        return FileUtil.newFile(DATA_CACHE, key.hashCode().toString() + "", mContent)
    }

    fun remove(key: String): Boolean {
        val image = get(key)
        return image.delete()
    }

    fun clear(): Boolean {
        return cacheSize?.let { size ->
            cacheDir?.let { dir ->
                lastUsageDates.clear()
                size.set(0)
                val files = dir.listFiles()
                if (files != null) {
                    for (f in files) {
                        f.delete()
                    }
                }
                true
            } ?: false
        } ?: false
    }


    /**
     * 移除旧的文件
     *
     * @return
     */
    private fun removeNext(): Long {
        if (lastUsageDates.isEmpty()) {
            return 0
        }
        var oldestUsage: Long? = null
        var mostLongUsedFile: File? = null
        val entries: Set<Map.Entry<File, Long>> = lastUsageDates.entries
        synchronized(lastUsageDates) {
            for ((key, lastValueUsage) in entries) {
                if (mostLongUsedFile == null) {
                    mostLongUsedFile = key
                    oldestUsage = lastValueUsage
                } else {
                    if (lastValueUsage < oldestUsage!!) {
                        oldestUsage = lastValueUsage
                        mostLongUsedFile = key
                    }
                }
            }
        }
        val fileSize = calculateSize(mostLongUsedFile)
        if (mostLongUsedFile!!.delete()) {
            lastUsageDates.remove(mostLongUsedFile)
        }
        return fileSize
    }

    private fun calculateSize(file: File?): Long {
        return file!!.length()
    }

    fun setUserLastDate() {
        mMMKVManager?.setUserLastDate(lastUsageDates)
    }
}